<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SVG to JPEG/PNG</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            font-size: 16px;
        }
        textarea, input, button, select {
            font-size: 16px;
        }
        #dropZone {
            width: 100%;
            height: 150px;
            border: 2px dashed #ccc;
            border-radius: 5px;
            padding: 10px;
            margin: 10px 0;
            position: relative;
            box-sizing: border-box;
        }
        #dropZone.dragover {
            border-color: #000;
            background-color: #f0f0f0;
        }
        #svgInput {
            width: 100%;
            height: 100%;
            border: none;
            resize: none;
            box-sizing: border-box;
        }
        #imageContainer {
            margin-top: 20px;
            text-align: center;
        }
        #convertedImage {
            max-width: 90%;
            cursor: pointer;
            transition: max-width 0.3s ease;
            border: 2px dashed #666;
        }
        #convertedImage.full-size {
            max-width: unset;
        }
        #base64Output {
            word-break: break-all;
            white-space: pre-wrap;
        }
        .option-group {
            margin-bottom: 10px;
        }
        #fileInput {
            margin-bottom: 10px;
        }
        #downloadLink, #loadExampleLink {
            display: inline-block;
            margin-top: 10px;
            margin-right: 10px;
        }
        #widthInput, #paddingInput {
            width: 60px;
        }
        #bgColor {
            vertical-align: middle;
        }
        #fileSize {
            margin-left: 10px;
        }
    </style>
</head>
<body>
    <h1>SVG to JPEG/PNG</h1>
    <input type="file" id="fileInput" accept=".svg">
    <a href="https://gist.githubusercontent.com/simonw/aedecb93564af13ac1596810d40cac3c/raw/83e7f3be5b65bba61124684700fa7925d37c36c3/tiger.svg" id="loadExampleLink">Load example image</a>
    <div id="dropZone">
        <textarea id="svgInput" placeholder="Paste your SVG code here or drag & drop an SVG file"></textarea>
    </div>
    <div class="option-group">
        <label>
            <input type="radio" name="format" value="image/jpeg" checked> JPEG
        </label>
        <label>
            <input id="pngRadio" type="radio" name="format" value="image/png"> PNG
        </label>
    </div>
    <div class="option-group">
        <label for="bgColor">Background Color:</label>
        <input type="color" id="bgColor" value="#ffffff">
        <label>
            <input type="checkbox" id="transparentBg"> Transparent
        </label>
    </div>
    <div class="option-group">
        <label for="widthInput">Output Width:</label>
        <input type="number" id="widthInput" value="800" min="1">
    </div>
    <div class="option-group">
        <label for="paddingInput">Padding:</label>
        <input type="number" id="paddingInput" value="0" min="0">
        <span>px</span>
    </div>
    <button id="convertButton" onclick="convertSvgToImage()">Convert SVG</button>
    <div id="imageContainer"></div>
    <a id="downloadLink" style="display: none;">Download Image</a>
    <span id="fileSize"></span>
    <div id="output" style="display: none;">
      <h2>Base64 Image Tag:</h2>
      <button id="copyImageButton" onclick="copyBase64Tag()">Copy image tag</button>
      <pre id="base64Output"></pre>
    </div>
    <script>
        const dropZone = document.getElementById('dropZone');
        const svgInput = document.getElementById('svgInput');
        const fileInput = document.getElementById('fileInput');
        const widthInput = document.getElementById('widthInput');
        const paddingInput = document.getElementById('paddingInput');
        const loadExampleLink = document.getElementById('loadExampleLink');
        const bgColor = document.getElementById('bgColor');
        const transparentBg = document.getElementById('transparentBg');
        const fileSizeSpan = document.getElementById('fileSize');
        const outputDiv = document.getElementById('output');
        const copyImageButton = document.getElementById('copyImageButton');
        const formatRadios = document.querySelectorAll('input[name="format"]');

        // ===== Hash <-> Text Sync Helpers =====
        function getTextFromHash() {
            if (!location.hash || location.hash.length <= 1) return null;
            try {
                return decodeURIComponent(location.hash.slice(1));
            } catch (e) {
                console.warn('Could not decode hash:', e);
                return null;
            }
        }
        function setHashFromText(text) {
            // Avoid spamming history with each render
            const encoded = encodeURIComponent(text);
            const target = '#' + encoded;
            if (location.hash !== target) {
                if (history.replaceState) {
                    history.replaceState(null, '', target);
                } else {
                    location.hash = encoded;
                }
            }
        }
        function loadFromHashIfPresent() {
            const text = getTextFromHash();
            if (text) {
                svgInput.value = text;
                convertSvgToImage();
            }
        }
        window.addEventListener('hashchange', () => {
            const text = getTextFromHash();
            if (text !== null) {
                svgInput.value = text;
                convertSvgToImage();
            }
        });

        // Add event listeners for instant preview updates
        paddingInput.addEventListener('input', debounce(convertSvgToImage, 300));
        widthInput.addEventListener('input', debounce(convertSvgToImage, 300));
        bgColor.addEventListener('input', debounce(convertSvgToImage, 300));
        formatRadios.forEach(radio => {
            radio.addEventListener('change', convertSvgToImage);
        });
        transparentBg.addEventListener('change', convertSvgToImage);

        // Debounce function to prevent too many updates
        function debounce(func, wait) {
            let timeout;
            return function() {
                const context = this;
                const args = arguments;
                clearTimeout(timeout);
                timeout = setTimeout(() => {
                    func.apply(context, args);
                }, wait);
            };
        }

        // Load example image functionality
        loadExampleLink.addEventListener('click', (e) => {
            e.preventDefault();
            const exampleSvgUrl = loadExampleLink.href;
            fetch(exampleSvgUrl)
                .then(response => response.text())
                .then(data => {
                    svgInput.value = data;
                    convertSvgToImage(); // Update preview with the loaded example
                })
                .catch(error => {
                    console.error('Error loading example SVG:', error);
                    alert('Failed to load example SVG. Please try again later.');
                });
        });

        // Color and transparency handling
        bgColor.addEventListener('input', () => {
            transparentBg.checked = false;
        });
        transparentBg.addEventListener('change', () => {
            if (transparentBg.checked) {
                bgColor.value = "#ffffff";
                pngRadio.click();
            }
        });

        // Drag and drop functionality
        dropZone.addEventListener('dragover', (e) => {
            e.preventDefault();
            dropZone.classList.add('dragover');
        });
        dropZone.addEventListener('dragleave', () => {
            dropZone.classList.remove('dragover');
        });
        dropZone.addEventListener('drop', (e) => {
            e.preventDefault();
            dropZone.classList.remove('dragover');
            const file = e.dataTransfer.files[0];
            if (file && file.type === 'image/svg+xml') {
                readFile(file);
            }
        });

        // File input functionality
        fileInput.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (file && file.type === 'image/svg+xml') {
                readFile(file);
            }
        });

        function readFile(file) {
            const reader = new FileReader();
            reader.onload = (e) => {
                svgInput.value = e.target.result;
                convertSvgToImage(); // Update preview with the loaded file
            };
            reader.readAsText(file);
        }

        function convertSvgToImage() {
            let svgContent = document.getElementById('svgInput').value;

            // If there's no SVG content, don't try to convert (and clear preview)
            if (!svgContent.trim()) {
                document.getElementById('imageContainer').innerHTML = '';
                document.getElementById('downloadLink').style.display = 'none';
                document.getElementById('fileSize').textContent = '';
                document.getElementById('base64Output').textContent = '';
                document.getElementById('output').style.display = 'none';
                return;
            }

            const imageContainer = document.getElementById('imageContainer');
            const base64Output = document.getElementById('base64Output');
            const downloadLink = document.getElementById('downloadLink');
            const format = document.querySelector('input[name="format"]:checked').value;
            const newWidth = parseInt(widthInput.value) || 800;
            const padding = parseInt(paddingInput.value) || 0;

            // Clear previous content
            base64Output.textContent = '';
            downloadLink.style.display = 'none';
            fileSizeSpan.textContent = '';

            // Extract the SVG element, ignoring any surrounding content
            const lowerContent = svgContent.toLowerCase();
            const svgStart = lowerContent.indexOf('<svg');
            const svgEnd = lowerContent.lastIndexOf('</svg>');

            if (svgStart === -1 || svgEnd === -1) {
                alert('Invalid SVG input');
                return;
            }

            svgContent = svgContent.slice(svgStart, svgEnd + '</svg>'.length);

            // Create a temporary SVG element
            const svgElement = new DOMParser().parseFromString(svgContent, 'image/svg+xml').documentElement;

            if (!svgElement || svgElement.nodeName !== 'svg') {
                alert('Invalid SVG input');
                return;
            }

            // Get SVG viewBox
            let viewBox = svgElement.getAttribute('viewBox');
            let width, height;
            if (viewBox) {
                [, , width, height] = viewBox.split(' ').map(Number);
            } else {
                width = parseInt(svgElement.getAttribute('width')) || 300;
                height = parseInt(svgElement.getAttribute('height')) || 150;
            }

            // Calculate new dimensions with padding
            const aspectRatio = width / height;
            const contentWidth = newWidth;
            const contentHeight = Math.round(contentWidth / aspectRatio);

            // Total canvas dimensions including padding
            const totalWidth = contentWidth + (padding * 2);
            const totalHeight = contentHeight + (padding * 2);

            // Create off-screen canvas
            const canvas = document.createElement('canvas');
            canvas.width = totalWidth;
            canvas.height = totalHeight;

            // Draw SVG on canvas
            const ctx = canvas.getContext('2d');

            // Set background color if not transparent
            if (!transparentBg.checked) {
                ctx.fillStyle = bgColor.value;
                ctx.fillRect(0, 0, totalWidth, totalHeight);
            }

            const svgBlob = new Blob([svgContent], {type: 'image/svg+xml;charset=utf-8'});
            const URL_ = window.URL || window.webkitURL || window;
            const svgUrl = URL_.createObjectURL(svgBlob);

            const img = new Image();
            img.onload = function() {
                // Draw the image with padding
                ctx.drawImage(img, padding, padding, contentWidth, contentHeight);
                URL_.revokeObjectURL(svgUrl);

                // Convert to selected format
                const imageDataUrl = canvas.toDataURL(format, 0.9);

                // Calculate file size
                const fileSizeInBytes = Math.round((imageDataUrl.length * 3) / 4);
                const fileSizeInKB = (fileSizeInBytes / 1024).toFixed(2);

                // Display converted image
                imageContainer.innerHTML = '';  // Clear previous image
                const convertedImg = document.createElement('img');
                convertedImg.src = imageDataUrl;
                convertedImg.id = 'convertedImage';
                convertedImg.onclick = toggleImageSize;
                imageContainer.appendChild(convertedImg);

                // Set up download link and display file size
                downloadLink.href = imageDataUrl;
                downloadLink.download = `converted_image.${format === 'image/jpeg' ? 'jpg' : 'png'}`;
                downloadLink.style.display = 'inline-block';
                fileSizeSpan.textContent = `(${fileSizeInKB} KB)`;

                // Display base64 image tag
                const imgTag = `<img src="${imageDataUrl}" alt="Converted ${format === 'image/jpeg' ? 'JPEG' : 'PNG'}" width="${totalWidth}" height="${totalHeight}">`;
                base64Output.textContent = imgTag;
                outputDiv.style.display = 'block';

                // ✅ Update URL hash with current textarea contents AFTER a successful render
                setHashFromText(svgInput.value);
            };
            img.src = svgUrl;
        }

        function toggleImageSize() {
            const img = document.getElementById('convertedImage');
            if (img) img.classList.toggle('full-size');
        }

        function copyBase64Tag() {
            const base64Output = document.getElementById('base64Output');
            const range = document.createRange();
            range.selectNode(base64Output);
            window.getSelection().removeAllRanges();
            window.getSelection().addRange(range);
            document.execCommand('copy');
            window.getSelection().removeAllRanges();
            const origText = copyImageButton.innerText;
            copyImageButton.innerText = 'Copied to clipboard';
            setTimeout(() => {
                copyImageButton.innerText = origText;
            }, 2000);
        }

        // On first load, if a hash fragment exists, use it to populate and render
        window.addEventListener('DOMContentLoaded', loadFromHashIfPresent);
    </script>
</body>
</html>
